13
תגובות
המחלקה הזאת היא מחלקה שיורשת מPDO ועובדת אם מסד נתונים
המחלקה:
<?php
[b][/b]
class Sidox_Datebase extends PDO {

    private $_bind;     #Linking the database with data
   private $_search;   #Search Settings
   protected $_table;  #Save a database table

    function __construct($dsn, $username, $password, $table) {
        parent::__construct($dsn, $username, $password);
        $this->_table = $table;
    }

    /*
     * set in _bind name and value
     */


    function __set($name, $value) {
        $this->_bind['name'][] = " `$name` ";
        $this->_bind['value'][] = " '$value' ";
    }

    /*
     * Insert into database
     */


    public function save() {
        $sql = 'INSERT INTO `' . $this->_table . '` (
               '
. implode(',', $this->_bind['name']) . ' ) VALUES (
               '
. implode(',', $this->_bind['value']) . ' )';

        $this->clean();
        return $this->query($sql);
    }

    /*
     * Update into database
     */


    public function update() {
        $sql = null;
        foreach ($this->_bind['name'] as $key => $value) {
            $sql[] = " {$this->_bind['name'][$key]} = {$this->_bind['value'][$key]} ";
        }

        $sql = 'UPDATE `' . $this->_table . '` SET ' . implode(' , ', $sql) . ' WHERE ' . implode(' AND ', $this->_search);

        $this->clean();
        return $this->query($sql);
    }

    /*
     * Delete from database
     */


    public function delete() {

        $sql = 'DELETE FROM `' . $this->_table . '` WHERE ' . implode(' AND ', $this->_search);
        $this->clean();

        $row = $this->query($sql);
        return $row->fetch();
    }

    /*
     * set search settings
     */


    public function setWhere($name, $value) {
        $this->_search[] = " `$name` = '$value' ";
        return $this;
    }

    /*
     * get rows with settings
     */


    public function getRow() {

        $sql = 'SELECT * FROM `' . $this->_table . '` WHERE ' . implode(' AND ', $this->_search);
       $this->clean();

        $row = $this->query($sql);
        return $row->fetch();
    }

    /*
     * clean all data in class
     */


    public function clean() {
        $this->_search = null;
        $this->_bind = array();
    }
    /*
     * get all from database
     */

    public function getAll() {

        $sql = 'SELECT * FROM `' . $this->_table;
        $row = $this->query($sql);
        return $row->fetchAll();
    }

}


דוגמה לשימוש:
מסד נתונים לדוגמה:
CREATE TABLE IF NOT EXISTS `demo` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) NOT NULL,
  `password` varchar(32) NOT NULL,
  `email` varchar(100) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

דוגמה לשימוש במחלקה
<?php
 $db = Sidox_Datebase("mysql:host=localhost;dbname=demo", 'root', '', 'demo');
//Insert to db
$db->username = 'pol';
$db->password = 'pass';
$db->email = '[email protected]';
$db->save();

$db->username = 'pol1';
$db->password = 'pass1';
$db->email = '[email protected]';
$db->save();


$row =$db->setWhere('name','pol')->setWhere('password','pass')->getRow(): //can used to login...

echo "<pre>";
print_r($row);
echo "<br />";
$row = $db->getAll();
print_r($row);

$db->username = 'pol2';
$db->password = 'pass2';
$db->email = '[email protected]';
$db->setWhere('name','pol')->update();
//now pol is pol2
$db->setWhere('name','pol')->delete();

13 תשובות

avatar ענה cthulhu ב 28 ליולי 2012 #

1) למה המתודה setWhere קובעת בדיקה האם הערכים זהים? מה תעשה כשתרצה לבדוק הם הערך הראשון גדול מהשני?
תעביר ל-setWhere ארגומנט אחד שיהיה ביטוי שיתאים ל-WHERE, כלומר משהו כזה:

setWhere('name > pol')


2) לא ברור לי הקשר הלוגי של המתודות שלך. לדוגמה, הקוד הזה:
$db->setWhere('name','pol')

לא אומר כלום והוא לא תקין. אתה אומר "המסד-קובע תנאי-קובע תנאי-מוציא שורה". זה אמור להיות "מסד-שורות שצריך לקחת-קובע תנאי (אולי מס' תנאי במכה אחת)-מוציא שורה".

3) במקום __set וכל הלולאות שאתה עושה, צור את המתודות שיקבלו ארגומנטים דינמיים ושאוב אותם באמצעות func_get_args. זה מתאים למקרים שבהם אתה לא יודע את כמות הפרמטרים שתקבל. המתודות שלך כרגע נראות גרוע מאוד, והמחלקה עצמה גם כן.

תלמד לכתוב מתודות לטוח ארוך, כלומר שהן יהיו יותר גמישות ויותר אוניברסליות. אני לא הייתי משתמש ב-wrapper שכתבת.

avatar ענה pol292 ב 28 ליולי 2012 #

תודה לא חשבתי על זה שיניתי את הGETROW והורדתי את הGETALLROWS

public function getRows()
    {
        $sql = 'SELECT * FROM `' . $this->_table .'` ';

        if (func_num_args() > 0)
            $sql .= ' WHERE ' . implode(' AND ', func_get_args());
       
        $row = $this->query($sql);
        return $row->fetch();

    }

עכשיו יש לי שאלה אחרת איזה פונקציה שאני יכניס :
getRows('name = pol')

וזה יהפוך את הname = pol ל 'name` = 'pol`?
הפתרון שלי לזה הוא לולאה אבל ניראה לי יש משהו שיכול לעזור בלי

avatar ענה bnayal ב 28 ליולי 2012 #

לא הבנתי, אתה מנסה לממש ORM משלך?
מה המטרה של המחלקה הזאת?

avatar ענה pol292 ב 28 ליולי 2012 #

כן משהו פשוט לשימוש

avatar ענה intval ב 29 ליולי 2012 #

בתור שיפור תעשה ככה שיהיה אפשר ליצור מופעים מהמחלקה שמקושרים לטבלאות שונות.
כלומר מחלקת user שיורשת מהמחלקה שלך תיגש אל טבלת users
מחלקה אחרת שיורשת מהמחלקה הזו תיגש לטבלה אחרת

avatar ענה pol292 ב 01 לאוגוסט 2012 #

הקוונה לפי שם המחלקה?

avatar ענה intval ב 01 לאוגוסט 2012 #

עדיף שלא. אבל לפי מאפיין של מחלקה - בהחלט אפשר.

avatar ענה pol292 ב 10 לאוגוסט 2012 #

שידרגתי את זה קצת יש עוד משהו שכידי להוסיף?
המחלקה אמורה להיות חלק בתוך FRAMEWORK שאני עובד אליו אז אני רוצה שזה היה הכי פשוט לשימוש

<?php

/*
 * **************************
 *     Sidox db model      *
 * **************************
 *
 * how to use:
 * 1)connected to sql server
 * demo for mysql:
 *      $obj = new Sidox_Model_Database(
 *      "mysql:host=localhost;dbname=pol", 'root', 'pass','table'(=null)
 *      );
 * 2)set table
 *      $obj->table = "tablename";
 * 3)for add new information in db use
 *      $obj->dbColum = 'x';
 *      $obj->dbColum2 = 'y';
 *      $obj->save();
 * 4)for update information in db use
 *      $obj->update();
 *      $obj->dbColum = 'y';
 *      $obj->dbColum2 = 'x';
 *      $obj->save('dbColum = x','dbColum2 = y');
 * 5)delete information
 *      $obj->delete('dbColum = y','dbColum2 = x');
 * 6)get information
 *      $obj->getRows('dbColum = y','dbColum2 = x');
 *      $obj->getRows(); //get all
 * 7)order by and limit
 *      $obj->order('dbColum','DESC')->limit(0,2)->getRows('dbColum = y','dbColum2 = x');
 *      $obj->order('dbColum','DESC')->limit(0,2)->getRows();
 */


class Sidox_Model_Database extends PDO {

    private $_data = null;      // @param string Linking the database with data
    private $_update = false;   // @param bool var use update in function save
    private $_scan = null;
    public $table = null;       // @param string database table

    function __construct($dsn, $username, $password, $table = null) {
        parent::__construct($dsn, $username, $password);
        $this->table = $table;
    }

    /*
     * save params in $_data
     * @param $name name of db column
     * @param $value the colum value
     */


    function __set($name, $value) {

        if ($this->_action == 'update') {
            $this->_data[] = '`' . $name . '` = \'' . $value . '\'';
        }
        $this->_data[$name] = " '$value' ";
    }

    /*
     * add mode: save in db new information
     * update mode: update the information
     * @param $_data save the information
     * @param $_update save the mode of function (true = update, false = add)
     * @param func_args where to scan for update
     * @param $table db table
     * @return false or query
     */


    public function save() {
        if ((empty($this->_data)) && (empty($this->table))) {
            return false;
        } elseif (($this->_update) && (func_num_args() > 0)) {
            //action update
            $rtn = $this->query(
                    'UPDATE `' . $this->table . '` SET ' .
                    implode(' , ', $this->_data) .
                    $this->scanWhere(func_get_args())
            );

            $this->_data = null;
            $this->_update = false;
            return $rtn;
        } elseif ($this->_update == false) {
            //action add
            $rtn = $this->query(
                    'INSERT INTO `' . $this->table . '` (
                    '
. implode(' , ', array_keys($this->_data)) . ' ) VALUES (
                    '
. implode(' , ', $this->_data) . ' )'
            );

            $this->_data = null;
            return $rtn;
        }
        return false;
    }

    /*
     * active the update mode in save function
     * @param $_update get true
     */


    public function update() {
        $this->_update = true;
    }

    /*
     * delete db row
     * @param func_args
     * @return the query connection
     *      
     */


    public function delete() {
        if (func_num_args() > 0)
            return $this->query(
                            'DELETE FROM `' . $this->table .
                            $this->scanWhere(func_get_args())
            );
    }

    /*
     * get DB rows
     * @param func_args or null
     * @return the query connection
     */


    public function getRows() {
        $sql = 'SELECT * FROM `' . $this->table . '` ';

        if (func_num_args() > 0)
            $sql .= $this->scanWhere(func_get_args());
        if (!empty($this->_sets)) {

            $sql .= " " . $this->_sets;
            unset($this->_sets);
        }

        unset($this->_scan);
        return $this->query($sql);
    }

    /*
     * Order By
     * @param string $order what order
     * @param string $type is ASC or DESC
     * @param $_sets test if set if true function die
     * @return $this
     */


    public function order($order, $type = 'ASC') {
        if (isset($this->_sets['order'])) {
            return false;
        }
        $this->_scan .= ' ORDER BY ' . $order . ' ' . $type . ' ';

        $this->_sets['order'] = null;
        return $this;
    }

    /*
     * limit list
     * @param int $limit start limit list or mach of limit
     * @param int $endLimit end the limit list
     * @param $_sets test if set if true function die
     * @return $this
     */


    public function limit($limit, $endLint = null) {
        if (isset($this->_sets['limit'])) {
            return false;
        }
        if (!empty($endLint))
            $this->_scan .= ' LIMIT ' . $limit . ',' . $endLint;
        else
            $this->_scan .= ' LIMIT ' . $limit;

        $this->_sets['limit'] = null;
        return $this;
    }

    /*
     * @param Array $scanArgs where scan
     * @return where to scan
     */


    private function scanWhere($scanArgs) {
        for ($i = 0; $i < sizeof($scanArgs); $i++) {
            sscanf($scanArgs[$i], '%s %s %s', $key, $operator, $value);
            $scanArgs[$i] = ' `' . $key . '` ' . $operator . ' \'' . $value . '\'';
        }
        return ' WHERE ' . implode(' AND ', $scanArgs);
    }

}

avatar ענה intval ב 11 לאוגוסט 2012 #

השיפור נראה נחמד. כל הכבוד :)
מה שכן, הייתי ממליץ לך לחשוב עד כמה נוח להישתמש במחלקה הזו.
מאוד לא אינטואיטיבי לזכור קודם להעביר ל x->update ואז לעשות save
חוץ מזה למפתח בכלל לא צריך להיות אכפת אם זה update או insert. שהמחלקה תחליט לבד.

בדרך כלל נהוג לעשות ככה, שכל מופע של מחלקה מייצג שורה אחת במסד שאיתה אפשר לעבוד.
מכאן הקוד שיוצא נראה בערך ככה:

$row1 = Table1::getById(4); // row with id=4
$row1->column = 'blabla';
$row1->save(); // makes an update

$newRow = new Table1();
$newRow->columnX = 'yo';
$newRow->save(); // makes an insert

$Alexes = Table1::where(['name' => 'alex']);
// $alexes = array of Table1 instances
$Alexes[0]->name = 'Tony';
$Alexes[0]->save(); // update


אל תשכח להוסיף טיפול בשגיאות, במקרה ולא הוזנו כל שדות החובה למשל.
בנוסף כל הכבוד על שימוש ב PHPDOCS. רק שים לב שאתה כותב את ה-DOC מעל למשתנה או המטודה ולא בצד שלה, אחרת העורך חושב שזה ה-DOC של המשתנה הבא.

avatar ענה pol292 ב 11 לאוגוסט 2012 #

כל הסיפור אם הUPDATE גם אני לא אהבתי אבל זאת הדרך היחידה שחשבתי שאני יוכל להיפתר מלולאה
פשוט אין לי רעיון איך להפריד בין מערך כזה מבלי להשתמש בלולאה:

array(
'username' => 'pol'
'password' => 'pass'
'email' => '[email protected]'
)

כך שיצא לאחר ההפרדה `username`='pol`,`password`='pass',`email`= '[email protected]'
הפתרון היחיד שהיה לי לזה שימוש בלולאת FOR

avatar ענה intval ב 11 לאוגוסט 2012 #

כנראה שזה יהיה foreach אבל אין שום בעיה עם לולאה.
רק על תשכח לטפל ב sql injection

$x->name = "O'connor";

avatar ענה pol292 ב 11 לאוגוסט 2012 #

תהיה לי מחלקה שאוטומטית מטפלת בכל הקלטים ככה שלא תהיה לי אם זה בעיה היא מנתרת את כל הבעיות

avatar ענה pol292 ב 11 לאוגוסט 2012 #

זהו סידרתי את זה ופשוט מעכשיו צריך לרשום save() ברגע שבSAVE יש הגדרות חיפוש הוא מתייחס לזה כעל UPDATE
יש עוד משהו חשוב שכידי להוסיף שיקל על העבודה?

<?php

/*
 * **************************
 *     Sidox db model      *
 * **************************
 *
 * how to use:
 * 1)connected to sql server
 * demo for mysql:
 *      $obj = new Sidox_Model_Database(
 *      "mysql:host=localhost;dbname=pol", 'root', 'pass','table'(=null)
 *      );
 * 2)set table
 *      $obj->table = "tablename";
 * 3)for add new information in db use
 *      $obj->dbColum = 'x';
 *      $obj->dbColum2 = 'y';
 *      $obj->save();
 * 4)for update information in db use
 *      $obj->dbColum = 'y';
 *      $obj->dbColum2 = 'x';
 *      $obj->save('dbColum = x','dbColum2 = y');
 * 5)delete information
 *      $obj->delete('dbColum = y','dbColum2 = x');
 * 6)get information
 *      $obj->getRows('dbColum = y','dbColum2 = x');
 *      $obj->getRows(); //get all
 * 7)order by and limit
 *      $obj->order('dbColum','DESC')->limit(0,2)->getRows('dbColum = y','dbColum2 = x');
 *      $obj->order('dbColum','DESC')->limit(0,2)->getRows();
 */


class Sidox_Model_Database extends PDO {
    /*
     * @param (string) $_data Linking the database with data
     */


    private $_data = null;
    /*
     * @param (string) $_scan scan in db
     */

    private $_scan = null;
    /*
     * @param (string) $table database table
     */

    public $table = null;

    /*
     * use parent construct and set table
     */

    function __construct($dsn, $username, $password, $table = null) {
        parent::__construct($dsn, $username, $password);
        $this->table = $table;
    }

    /*
     * save params in $_data
     * @param $name name of db column
     * @param $value the colum value
     */


    function __set($name, $value) {

        if ($this->_action == 'update') {
            $this->_data[] = '`' . $name . '` = \'' . $value . '\'';
        }
        $this->_data[$name] = " '$value' ";
    }

    /*
     * add mode: save in db new information
     * update mode: update the information
     * @param $_data save the information
     * @param $_update save the mode of function (true = update, false = add)
     * @param func_args where to scan for update
     * @param $table db table
     * @param $rtn return data
     * @return false or query
     */


    public function save() {
        $rtn = false;
        if ((empty($this->_data)) && (empty($this->table))) {
            return false;
        } elseif (func_num_args() > 0) {
            //action update
            $update = null;
            foreach ($this->_data as $key => $value) {
                if (empty($update)) {
                    $update = " `{$key}` = '{$value}'";
                    continue;
                }
                $update .= " , `{$key}` = '{$value} '";
            }
            $rtn = $this->query(
                    'UPDATE `' . $this->table . '` SET ' .
                    $update . $this->scanWhere(func_get_args())
            );
        } else {
            //action add
            $rtn = $this->query(
                    'INSERT INTO `' . $this->table . '` (
                    '
. implode(' , ', array_keys($this->_data)) . ' ) VALUES (
                    '
. implode(' , ', $this->_data) . ' )'
            );
        }
        $this->_data = null;
        return $rtn;
    }

    /*
     * delete db row
     * @param func_args
     * @return the query connection
     */


    public function delete() {
        if (func_num_args() > 0)
            return $this->query(
                            'DELETE FROM `' . $this->table .
                            $this->scanWhere(func_get_args())
            );
    }

    /*
     * get DB rows
     * @param func_args or null
     * @return the query connection
     */


    public function getRows() {
        $sql = 'SELECT * FROM `' . $this->table . '` ';

        if (func_num_args() > 0)
            $sql .= $this->scanWhere(func_get_args());
        if (!empty($this->_sets)) {

            $sql .= " " . $this->_sets;
            unset($this->_sets);
        }

        unset($this->_scan);
        return $this->query($sql);
    }

    /*
     * Order By
     * @param string $order what order
     * @param string $type is ASC or DESC
     * @param $_sets test if set if true function die
     * @return $this
     */


    public function order($order, $type = 'ASC') {
        if (isset($this->_sets['order'])) {
            return false;
        }
        $this->_scan .= ' ORDER BY ' . $order . ' ' . $type . ' ';

        $this->_sets['order'] = null;
        return $this;
    }

    /*
     * limit list
     * @param int $limit start limit list or mach of limit
     * @param int $endLimit end the limit list
     * @param $_sets test if set if true function die
     * @return $this
     */


    public function limit($limit, $endLint = null) {
        if (isset($this->_sets['limit'])) {
            return false;
        }
        if (!empty($endLint))
            $this->_scan .= ' LIMIT ' . $limit . ',' . $endLint;
        else
            $this->_scan .= ' LIMIT ' . $limit;

        $this->_sets['limit'] = null;
        return $this;
    }

    /*
     * @param Array $scanArgs where scan
     * @return where to scan
     */


    private function scanWhere($scanArgs) {
        for ($i = 0; $i < sizeof($scanArgs); $i++) {
            sscanf($scanArgs[$i], '%s %s %s', $key, $operator, $value);
            $scanArgs[$i] = ' `' . $key . '` ' . $operator . ' \'' . $value . '\'';
        }
        return ' WHERE ' . implode(' AND ', $scanArgs);
    }

}